home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
- * use is allowed under the terms of the DICE-LICENSE FILE,
- * DICE-LICENSE.TXT.
- */
-
- /*
- * MODULE.C
- *
- */
-
- #include "defs.h"
-
- #define LINE 0x4C494E45
-
- Prototype Module *CreateModule(FileNode *);
- Prototype int CreateSymbolTable(Module *);
- Prototype int ScanLibForInclusion(Module *);
- Prototype void CreateHunkListNodes(Module *, List *);
- Prototype void FinalCombineHunkListNodes(List *);
- Prototype void FixInternalSymbols(List *);
- Prototype void PIOptCombineIntoCode(List *);
-
- /*
- * Given a file node and a fully loaded file create a Module structure for
- * that node. Set the Node->ln_Type to the file node's type.
- *
- * This routine creates a *single* module .. that is, it stops if it reaches
- * a second hunk_unit.
- */
-
- Module *
- CreateModule(fn)
- FileNode *fn;
- {
- Module *mod = zalloc(sizeof(Module));
-
- ++MemNumModules;
- mod->Node.ln_Type = fn->Node.ln_Type;
- mod->FNode = fn;
-
- /*
- * Do a validity scan and incidently count the number of hunks you
- * find.
- */
-
- mod->ModBeg = (char *)fn->DPtr;
- {
- ulong *scan = fn->DPtr;
- ulong *scanEnd = (ulong *)((char *)fn->Data + fn->Bytes);
- long nl;
-
- /*
- * look for hunk_unit
- */
-
- if ((uword)FromMsbOrder(*scan) != 0x3E7)
- cerror(EFATAL_OBJECT_PARSE, fn->Node.ln_Name, (char *)fn->DPtr - (char *)fn->Data);
-
- nl = FromMsbOrder(scan[1] * 4);
- mod->Node.ln_Name = zalloc(nl + 1);
- movmem(scan + 2, mod->Node.ln_Name, nl);
- mod->Node.ln_Name[nl] = 0;
-
- scan += FromMsbOrder(scan[1]) + 2;
-
- /*
- * scan hunks for the module.
- */
-
- while (scan < scanEnd && (uword)FromMsbOrder(*scan) != 0x3E7) {
- ++mod->NumHunks; /* # hunks in module */
-
- if ((uword)FromMsbOrder(*scan) == 0x3E8) {
- scan += FromMsbOrder(scan[1]) + 2; /* skip hunk_name */
- }
-
- while (FromMsbOrder(*scan) != 0x3F2) { /* until we get a hunk_end */
- ulong len;
-
- switch((uword)FromMsbOrder(*scan)) {
- case 0x3E9: /* HUNK_CODE */
- case 0x3EA: /* HUNK_DATA */
- scan += FromMsbOrder(scan[1]) + 2;
- break;
- case 0x3EB: /* HUNK_BSS */
- scan += 2;
- break;
- case 0x3EC: /* HUNK_RELOC32 */
- case 0x3ED: /* HUNK_RELOC16-PC */
- case 0x3EE: /* HUNK_RELOC8 */
- case 0x3F8: /* HUNK_RELOC16-D (special) */
- ++scan;
- while (FromMsbOrder(*scan))
- scan += FromMsbOrder(*scan) + 2;
- ++scan;
- break;
- case 0x3EF: /* HUNK_EXT */
- case 0x3F0: /* HUNK_SYMBOL */
- ++scan;
- while ((len = FromMsbOrder(*scan)) != 0) {
- ubyte type = len >> 24;
-
- len &= 0x00FFFFFF;
- scan += len + 1;
-
- switch(type) {
- case 0: /* SYMB */
- case 1: /* DEF */
- case 2: /* ABS */
- case 3: /* RES */
- ++scan; /* skip value */
- break;
- case 130: /* COMMON (def)*/
- /*fatal("COMMON symbol not supported, module %s", fn->Node.ln_Name);*/
- ++scan; /* skip common size */
- break;
- case 135: /* REF32-pc */
- case 129: /* REF32 */
- case 131: /* REF16-pc */
- case 132: /* REF8 */
- case 134: /* REF16D */
- /* skip relocation info */
- scan += FromMsbOrder(scan[0]) + 1;
- break;
- default:
- cerror(EFATAL_UNKNOWN_SYMBOL_TYPE, type, fn->Node.ln_Name);
- }
- }
- ++scan; /* skip 0 terminator */
- break;
- case 0x3F1: /* HUNK_DEBUG */
- scan += FromMsbOrder(scan[1]) + 2;
- break;
- default:
- cerror(EFATAL_UNKNOWN_HUNK_TYPE, *scan, fn->Node.ln_Name);
- }
- }
- ++scan; /* skip hunk_end */
- }
- if (scan > scanEnd)
- cerror(EFATAL_OBJECT_SIZE_MISMATCH, fn->Node.ln_Name);
- }
-
- /*
- * Allocate some stuff
- */
-
- mod->Hunks = zalloc(sizeof(Hunk *) * mod->NumHunks);
- MemNumHunks += mod->NumHunks;
-
- /*
- * Do a load scan
- */
-
- {
- ulong *scan = fn->DPtr;
- ulong *scanEnd = (ulong *)((char *)fn->Data + fn->Bytes);
- short hunkNo = 0;
-
- /*
- * look for hunk_unit
- */
-
- if ((uword)FromMsbOrder(*scan) != 0x3E7)
- cerror(EFATAL_146);
- scan += FromMsbOrder(scan[1]) + 2;
-
- /*
- * scan hunks for the module.
- */
-
- while (scan < scanEnd && (uword)FromMsbOrder(*scan) != 0x3E7) {
- Hunk *hunk = zalloc(sizeof(Hunk));
- ++MemNumHunks;
-
- if (hunkNo >= mod->NumHunks)
- cerror(EFATAL_TOO_MANY_HUNKS);
-
- mod->Hunks[hunkNo] = hunk;
- hunk->HunkNo = hunkNo;
- hunk->Module = mod;
- NewList(&hunk->SymList); /* only used if SymOpt */
- ++hunkNo;
-
- /*
- * hunk name. If section name starts with 'far' or in
- * dummy flag to upper bits of hunkid to force the hunk
- * to remain outside normal data+bss small model combine.
- */
-
- if ((uword)FromMsbOrder(*scan) == 0x3E8) {
- long nl = FromMsbOrder(scan[1]) * 4;
- hunk->Node.ln_Name = zalloc(nl + 1);
- movmem(scan + 2, hunk->Node.ln_Name, nl);
- hunk->Node.ln_Name[nl] = 0;
- if (strnicmp(hunk->Node.ln_Name, "far", 3) == 0)
- hunk->HunkId |= HUNKIDF_FLAG;
- scan += FromMsbOrder(scan[1]) + 2; /* skip hunk_name */
- } else {
- hunk->Node.ln_Name = "";
- }
-
- /* until we get a hunk_end */
-
- while ((uword)FromMsbOrder(*scan) != 0x3F2) {
- ulong len;
-
- switch((uword)FromMsbOrder(*scan)) {
- case 0x3E9: /* HUNK_CODE */
- hunk->HunkId |= FromMsbOrder(*scan);
- hunk->Node.ln_Type = NT_CODE;
- hunk->Data = scan + 2;
- hunk->Bytes= FromMsbOrder(scan[1]) << 2;
- scan += FromMsbOrder(scan[1]) + 2;
- break;
- case 0x3EA: /* HUNK_DATA */
- hunk->HunkId |= FromMsbOrder(*scan);
- hunk->Node.ln_Type = NT_DATA;
- hunk->Data = scan + 2;
- hunk->Bytes= FromMsbOrder(scan[1]) << 2;
- scan += FromMsbOrder(scan[1]) + 2;
- break;
- case 0x3EB: /* HUNK_BSS */
- hunk->HunkId |= FromMsbOrder(*scan);
- hunk->Node.ln_Type = NT_BSS;
- hunk->Data = NULL;
- hunk->Bytes = FromMsbOrder(scan[1]) << 2;
- scan += 2;
- break;
- case 0x3F8: /* HUNK_RELOC16-D */
- hunk->Reloc16D = scan + 1;
- /* fall through */
- case 0x3EC: /* HUNK_RELOC32 */
- if (FromMsbOrder(*scan) == 0x3EC)
- hunk->Reloc32 = scan + 1;
- /* fall through */
- case 0x3ED: /* HUNK_RELOC16 */
- if (FromMsbOrder(*scan) == 0x3ED)
- hunk->Reloc16 = scan + 1;
- /* fall through */
- case 0x3EE: /* HUNK_RELOC8 */
- if (FromMsbOrder(*scan) == 0x3EE)
- hunk->Reloc8 = scan + 1;
- ++scan;
- while (FromMsbOrder(*scan))
- scan += FromMsbOrder(*scan) + 2;
- ++scan;
- break;
- case 0x3EF: /* HUNK_EXT */
- hunk->Ext = scan + 1;
- /* fall through */
- case 0x3F0: /* HUNK_SYMBOL */
- if (FromMsbOrder(*scan) == 0x3F0)
- hunk->Sym = scan + 1;
- ++scan;
- while ((len = FromMsbOrder(*scan)) != 0) {
- ubyte type = len >> 24;
-
- len &= 0x00FFFFFF;
- scan += len + 1;
-
- switch(type) {
- case 0: /* SYMB */
- case 1: /* DEF */
- case 2: /* ABS */
- case 3: /* RES */
- if (type != 2)
- ++hunk->ExtDefs;
- ++scan; /* skip value */
- break;
- case 130: /* COMMON */
- /*fatal("COMMON symbol not supported");*/
- /*++hunk->ExtDefs;*/
- ++scan; /* skip common size */
- break;
- case 135: /* REF32-pc */
- case 129: /* REF32 */
- case 131: /* REF16-pc */
- case 132: /* REF8 */
- case 134: /* REF16D */
- /* skip relocation info */
- scan += FromMsbOrder(scan[0]) + 1;
- break;
- }
- }
- ++scan; /* skip 0 terminator */
- break;
- case 0x3F1: /* HUNK_DEBUG */
- if (((DBInfo *)scan)->di_LINE == LINE)
- hunk->DbInfo = (DBInfo *)scan;
- scan += FromMsbOrder(scan[1]) + 2;
- break;
- }
- }
- ++scan; /* skip hunk_end */
- hunk->TotalBytes = hunk->Bytes;
- if (hunk->Node.ln_Type == 0)
- cerror(EERROR_NO_CODE_DATA_BSS, hunk->Node.ln_Name, hunk->Module->Node.ln_Name);
- }
- fn->DPtr = scan;
- if (hunkNo < mod->NumHunks)
- cerror(EFATAL_TOO_FEW_HUNKS);
- if (hunkNo > mod->NumHunks)
- cerror(EFATAL_TOO_MANY_HUNKS);
- mod->ModEnd = (char *)fn->DPtr;
- }
-
- return(mod);
- }
-
- /*
- * run SCAN_RELOC_SYMIN on all external symbol tables for all hunks in
- * this module.
- *
- * returns number of newly undefined symbols that have been created
- * (referencing symbols that are already undefined ... previously
- * referenced and still not defined, do not count in the count)
- */
-
- int
- CreateSymbolTable(mod)
- Module *mod;
- {
- short i;
- long r = 0;
-
- for (i = 0; i < mod->NumHunks; ++i)
- r += ScanHunkExt(mod->Hunks[i], SCAN_RELOC_SYMIN);
- return(r);
- }
-
- /*
- * returns true if this module, part of a library, contains definitions
- * used by previously loaded modules
- */
-
- int
- ScanLibForInclusion(mod)
- Module *mod;
- {
- short i;
-
- for (i = 0; i < mod->NumHunks; ++i) {
- if (ScanHunkExt(mod->Hunks[i], SCAN_RELOC_SYMCK))
- return(1);
- }
- return(0);
- }
-
- /*
- * This is the great coagulator... hlist begins empty. We allocate a
- * master HunkListNode for each 'hunk' in the final output, adding hunks
- * that appear in the module to the appropriate HunkListNode.
- *
- * We can never combine hunks with different HunkId's (including the
- * upper bits)
- *
- * We must also keep sections in order.
- *
- * Note that only hunks with the same HunkListNode may run PC relative
- * references to each other.
- */
-
- void
- CreateHunkListNodes(mod, hlist)
- Module *mod;
- List *hlist;
- {
- short i;
-
- for (i = 0; i < mod->NumHunks; ++i) {
- Hunk *hunk;
- Hunk *h;
- HunkListNode *hn;
-
- hunk = mod->Hunks[i];
-
- /*
- * Search for the hunk type & name amoung HunkListNode type and names.
- * If not found, append a new HunkListNode. Give HunkListNode's
- * priorities:
- * 64 NT_CODE
- * 32 NT_DATA
- * 16 NT_BSS
- */
-
- for (hn = GetHead(hlist); hn; hn = GetSucc(&hn->Node)) {
- if (hn->HunkId != hunk->HunkId)
- continue;
- #ifdef NOTDEF
- /*
- * if data or bss
- */
- if ((uword)hn->HunkId == (uword)hunk->HunkId) {
- if (hn->Node.ln_Type == NT_DATA || hn->Node.ln_Type == NT_BSS) {
- if (ResOpt) {
- cerror(EWARN_CANNOT_COAG_DATABSS);
- ResOpt = 0;
- }
- }
- }
- continue;
- }
- #endif
- /*
- * Ignore section names for -r or -pi/-pr
- */
-
- if (PIOpt || ResOpt)
- break;
-
- /*
- * Collect if the same section name
- */
-
- if (strcmp(hn->Node.ln_Name, hunk->Node.ln_Name) == 0)
- break;
-
- /*
- * collection of differently named hunks only works if -frag
- * is not specified AND the hunks are normal hunks (no upper
- * bits set)
- *
- * hunk names that begin with 'far' have a dummy upper bit set
- */
-
- if (FragOpt == 0 && (hunk->HunkId & 0xFFFF0000) == 0)
- break;
- }
- if (hn == NULL) {
- hn = zalloc(sizeof(HunkListNode));
- hn->Node.ln_Type = hunk->Node.ln_Type;
- hn->Node.ln_Name = hunk->Node.ln_Name;
- hn->HunkId = hunk->HunkId;
-
- switch(hn->Node.ln_Type) {
- case NT_CODE:
- hn->Node.ln_Pri = 64;
- break;
- case NT_DATA:
- hn->Node.ln_Pri = 32;
- break;
- case NT_BSS:
- hn->Node.ln_Pri = 16;
- break;
- default:
- hn->Node.ln_Pri = 8;
- break;
- }
- Enqueue(hlist, &hn->Node);
- NewList(&hn->HunkList);
- }
- /*
- * Put the hunk after other hunks of the same name.
- */
-
- for (h = GetHead(&hn->HunkList); h; h = GetSucc(&h->Node)) {
- if (strcmp(h->Node.ln_Name, hunk->Node.ln_Name) == 0)
- break;
- }
- while (h && strcmp(h->Node.ln_Name, hunk->Node.ln_Name) == 0)
- h = GetSucc(&h->Node);
-
- if (h) /* insert after last name that compared */
- h = GetPred(&h->Node); /* or head of list */
- else /* couldn't find anything, append to end */
- h = GetTail(&hn->HunkList);
-
- Insert(&hn->HunkList, &hunk->Node, &h->Node);
- hunk->HL = hn;
- hunk->HX = hn;
- hn->FinalExtDefs += hunk->ExtDefs;
- }
- }
-
- /*
- * If we are not running fragmented this routine places all BSS sections
- * after DATA sections. Currently this is only done for unqualified
- * hunks (e.g. that can go into any type of memory).
- *
- * e.g. this routine combines the DATA and BSS sections
- *
- * note that due to enqueue priority DATA sections will come before BSS
- * sections.
- *
- * note that any section name beginning with 'far' has a HUNKIDF_FLAG
- * set in its HunkId so it will not be improperly combined.
- */
-
- void
- FinalCombineHunkListNodes(hlist)
- List *hlist;
- {
- HunkListNode *hn;
- HunkListNode *hn_next;
- HunkListNode *hndata = NULL;
- Hunk *h;
-
- if (FragOpt)
- return;
- for (hn = GetHead(hlist); hn; hn = hn_next) {
- hn_next = GetSucc(&hn->Node);
- if (hn->Node.ln_Type == NT_DATA && (hn->HunkId & 0xFFFF0000) == 0) {
- hndata = hn;
- for (h = (Hunk *)GetHead(&hn->HunkList); h; h = (Hunk *)GetSucc(&h->Node)) {
- h->Flags |= HF_SMALLDATA;
- }
- }
-
- if (hn->Node.ln_Type == NT_BSS && (hn->HunkId & 0xFFFF0000) == 0) {
- if (hndata) {
- Remove(&hn->Node);
- while ((h = (Hunk *)RemHead(&hn->HunkList)) != NULL) {
- AddTail(&hndata->HunkList, &h->Node);
- h->HL = hndata;
- h->HX = hndata;
- h->Flags |= HF_DATABSS | HF_SMALLDATA;
- hndata->FinalExtDefs += h->ExtDefs;
- }
- } else {
- for (h = (Hunk *)GetHead(&hn->HunkList); h; h = GetSucc(&h->Node))
- h->Flags |= HF_DATABSS;
- hn->Node.ln_Type = NT_DATA;
- hn->HunkId = 0x3EA;
- hndata = hn;
- }
- }
- }
- }
-
-
- /*
- * This routine fixes the symbol table for BSS sections combined with DATA
- * sections. Note that if we are Frag'd there are no combined BSS sections.
- *
- * Only unqualified sections are considered. e.g. a CHIP ram section is not
- * considered. qualified sections are assumed to be referenced with far
- * declarations.
- *
- * It is still possible to have some far data & bss hunks. The combine
- * only applies to the first two.
- */
-
- void
- FixInternalSymbols(list)
- List *list;
- {
- HunkListNode *data = NULL;
- HunkListNode *bss = NULL;
- HunkListNode *code = NULL;
- Hunk *hunk;
-
- if (FragOpt)
- return;
-
- {
- HunkListNode *hn;
- for (hn = GetHead(list); hn; hn = GetSucc(&hn->Node)) {
- if ((hn->HunkId & 0xFFFF0000) == 0) {
- if (hn->Node.ln_Type == NT_CODE)
- code = hn;
- if (hn->Node.ln_Type == NT_DATA) {
- if (data == NULL)
- data = hn;
- else
- cerror(EFATAL_556);
- }
- if (hn->Node.ln_Type == NT_BSS) {
- if (bss == NULL)
- bss = hn;
- else
- cerror(EFATAL_562);
- }
- }
- }
- }
-
- if (data == NULL) /* no data anyway */
- return;
- if (bss && !FragOpt)
- cerror(EFATAL_571);
-
- hunk = GetHead(&data->HunkList);
- if (hunk == NULL)
- cerror(EFATAL_DATA_HUNK_EMPTY);
-
- BssLenSym->Hunk = hunk;
- BssLenSym->Value= data->AddSize >> 2;
-
- if (SymOpt) {
- AddTail(&hunk->SymList, (Node *)&BssLenSym->Node);
- BssLenSym->Flags |= SYMF_SYMLIST;
- }
-
- if (AbsWordOpt || PIOpt) {
- /*
- * AbsWordOpt: __ABSOLUTE_BAS address already set to absolute value
- */
- if (code && (hunk = GetTail(&code->HunkList))) {
- DataBasSym->Type = 1;
- DataBasSym->Hunk = hunk;
- DataBasSym->Value= /* hunk->Offset + */ hunk->TotalBytes;
-
- /*
- * position independant option, __ABSOLUTE_BAS and __DATA_BAS
- * point to the same thing and reside in code hunk so can be
- * accessed PC-relative
- */
-
- if (PIOpt) {
- AbsoluteBasSym->Type = 1;
- AbsoluteBasSym->Hunk = hunk;
- AbsoluteBasSym->Value= /* hunk->Offset + */ hunk->TotalBytes;
- }
- }
- } else {
- /*
- * must set __ABSOLUTE_BAS address to location of real data, but
- * only if the symbol exists (e.g. ResOpt == 0)
- */
- if (AbsoluteBasSym) {
- AbsoluteBasSym->Type = 1;
- AbsoluteBasSym->Hunk = hunk;
- }
-
- DataBasSym->Type = 1;
- DataBasSym->Hunk = hunk;
- }
- DataLenSym->Value = data->FinalSize >> 2;
- if (SymOpt) {
- AddTail(&hunk->SymList, (Node *)&DataBasSym->Node);
- AddTail(&hunk->SymList, (Node *)&DataLenSym->Node);
- DataBasSym->Flags |= SYMF_SYMLIST;
- DataLenSym->Flags |= SYMF_SYMLIST;
-
- if (AbsoluteBasSym) {
- AddTail(&hunk->SymList, (Node *)&AbsoluteBasSym->Node);
- AbsoluteBasSym->Flags |= SYMF_SYMLIST;
- }
- }
-
- if (ResOpt)
- IsResSym->Value = 1;
- }
-
- /*
- * Position Independant option combine, Just before final output combine
- * all hunks into a single CODE hunk. However, offsets for DATA & BSS
- * hunks are NOT modified because DATA & BSS is still referenced A4-REL.
- *
- * There can be no 32 bit relocations
- */
-
- void
- PIOptCombineIntoCode(list)
- List *list;
- {
- HunkListNode *hn;
- HunkListNode *ht;
- Hunk *hunk;
-
- hn = RemHead(list);
- if (hn == NULL)
- return;
- if (hn->Node.ln_Type != NT_CODE) {
- cerror(EERROR_PI_EXPECTED_CODE);
- return;
- }
- while ((ht = RemHead(list)) != NULL) {
- if (ht->Node.ln_Type == NT_CODE) {
- cerror(EERROR_PI_EXPECTED_ONE_CODE);
- return;
- }
- while ((hunk = RemHead(&ht->HunkList)) != NULL) {
- if (hunk->Flags & HF_DATABSS)
- hn->AddSize += (hunk->TotalBytes + 3) & ~3;
- else
- hn->FinalSize += (hunk->TotalBytes + 3) & ~3;
- AddTail(&hn->HunkList, &hunk->Node);
- }
- }
- NumExtHunks = 1;
- AddHead(list, &hn->Node);
- }
-
-